package com.ug_project.spring_dict.Controllers

import com.fasterxml.jackson.datatype.joda.JodaModule
import com.fasterxml.jackson.module.kotlin.registerKotlinModule
import com.ug_project.spring_dict.DataAccess.AccountRepository
import com.ug_project.spring_dict.DataAccess.connectDb
import com.ug_project.spring_dict.Entities.SessionUser
import com.ug_project.spring_dict.Entities.User
import com.ug_project.spring_dict.WebApiV1
import io.ktor.application.*
import io.ktor.auth.*
import io.ktor.features.*
import io.ktor.http.HttpHeaders
import io.ktor.http.HttpMethod
import io.ktor.http.HttpStatusCode
import io.ktor.jackson.jackson
import io.ktor.locations.Location
import io.ktor.locations.Locations
import io.ktor.locations.location
import io.ktor.locations.put
import io.ktor.response.ApplicationSendPipeline
import io.ktor.response.header
import io.ktor.response.respond
import io.ktor.routing.get
import io.ktor.routing.post
import io.ktor.routing.route
import io.ktor.routing.routing
import io.ktor.sessions.Sessions
import io.ktor.sessions.cookie
import io.ktor.sessions.get
import io.ktor.sessions.sessions
import io.ktor.util.AttributeKey
import io.ktor.util.toMap
import org.jetbrains.exposed.sql.transactions.transaction


fun Application.accountModule() {
    install(DefaultHeaders)
    install(CORS){
        anyHost()
        method(HttpMethod.Options)
        method(HttpMethod.Put)
        method(HttpMethod.Get)
        method(HttpMethod.Delete)
        method(HttpMethod.Post)
        exposeHeader("*")
        header(HttpHeaders.Authorization)
        header("x-requested-with")
    }
    install(ContentNegotiation) {
        jackson {
            registerKotlinModule()
            registerModule(JodaModule().apply {

            })
        }
    }
//    install(Compression)
    install(Locations)
    //#endregion

    authentication {
        digest {
            realm = "SpringDict"
            userNameRealmPasswordDigestProvider = { userName, realm ->
                val user = AccountRepository().findByName(userName)
                digester.digest("$userName:$realm:${user?.signInPassword}".toByteArray())
            }
        }

//        install(object : ApplicationFeature<ApplicationCallPipeline, Unit, Unit> {
//            override val key: AttributeKey<Unit> by lazy { AttributeKey<Unit>("WWW-AJAX-AUTHENTICATE") }
//            override fun install(pipeline: ApplicationCallPipeline, configure: Unit.() -> Unit) {
//                pipeline.sendPipeline.intercept(ApplicationSendPipeline.After){
////                    val authHeader = context.response.headers[HttpHeaders.WWWAuthenticate]
//                    context.response.headers.allValues().forEach {k, vs ->
//                        println("$k: ${vs.joinToString()}")
//                    }
////                    if (authHeader != null){
////                        context.response.header("www-ajax-authenticate", authHeader)
////                    }
//                }
//            }
//        })
    }

    AccountRepository().createAdminIfNotExists(User(
            name = "admin",
            signInName = "admin",
            signInPassword = "admin",
            permission = User.ADMIN
    ))

    routing {
        location(WebApiV1::class) {
            route("Account") {
                //#region Register User
                @Location("")
                data class UserModel(val name: String, val signInName: String, val signInPassword: String)

                put<UserModel> {
                    if (it.signInPassword.length < 5) {
                        context.respond(HttpStatusCode.BadRequest)
                        return@put
                    }

                    val user = AccountRepository().insert(User(
                            name = it.name,
                            signInName = it.signInName,
                            signInPassword = it.signInPassword,
                            permission = User.USER
                    ))

                    context.response.status(HttpStatusCode.Created)
                    context.respond(user.id)

                }
                //#endregion

                authenticate {
                    //#region GetAllUser
                    get {
                        if (context.user()?.permission ?: 0 != User.ADMIN)
                        {
                            context.respond(HttpStatusCode.Unauthorized)
                            return@get
                        }
                        val users = transaction(connectDb()) {
                            val users = AccountRepository().getAllUser()
                            users
                        }

                        context.respond(users)
                    }
                    //#endregion

                    post("SignIn") {
                        val principal = context.digestAuthenticationCredentials()

                        val user = AccountRepository().findByName(principal?.userName ?: "") ?: return@post
                        user.signInPassword = "******"
                        context.respond(user)
                    }
                }
                get("/Okay"){
                    context.respond("Changed")
                }
            }
        }
    }
}

fun ApplicationCall.user() : User? = AccountRepository().findByName(this.digestAuthenticationCredentials()?.userName ?: "")
